/**
 * 认证服务
 * 提供用户注册、登录和认证相关功能
 */

const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');
const { User } = require('../models/User');
const { generateToken, verifyToken } = require('../utils/jwt');
const { logInfo, logError, logWarning } = require('../logger');
const { verifyCode } = require('./verificationService');

// 盐值轮数
const SALT_ROUNDS = 12;

/**
 * 用户注册服务
 * @param {Object} userData - 用户注册数据
 * @returns {Object} 包含用户信息和访问令牌的对象
 */
async function register(userData) {
  try {
    // 验证邮箱验证码
    if (!userData.verificationCode) {
      logWarning('用户注册失败：缺少验证码', { email: userData.email });
      throw new Error('请输入邮箱验证码');
    }

    const verificationResult = await verifyCode(userData.email, userData.verificationCode, 'register');
    if (!verificationResult.success) {
      logWarning('用户注册失败：验证码无效', { email: userData.email, error: verificationResult.error });
      throw new Error(verificationResult.error || '验证码无效');
    }

    // 检查邮箱是否已存在
    const existingUser = await User.findOne({
      where: {
        email: userData.email
      }
    });

    if (existingUser) {
      logWarning('用户注册失败：邮箱已存在', { email: userData.email });
      throw new Error('邮箱已被注册');
    }

    // 如果提供了用户名，检查用户名是否已存在
    if (userData.username) {
      const existingUsername = await User.findOne({
        where: {
          username: userData.username
        }
      });

      if (existingUsername) {
        logWarning('用户注册失败：用户名已存在', { username: userData.username });
        throw new Error('用户名已被使用');
      }
    }

    // 如果提供了手机号，检查手机号是否已存在
    if (userData.phone) {
      const existingPhone = await User.findOne({
        where: {
          phone: userData.phone
        }
      });

      if (existingPhone) {
        logWarning('用户注册失败：手机号已存在', { phone: userData.phone });
        throw new Error('手机号已被注册');
      }
    }

    // 对密码进行哈希处理
    const hashedPassword = await bcrypt.hash(userData.password, SALT_ROUNDS);

    // 创建用户
    const user = await User.create({
      uuid: uuidv4(),
      username: userData.username,
      email: userData.email,
      phone: userData.phone,
      name: userData.name || userData.username || userData.email.split('@')[0],
      avatarUrl: userData.avatarUrl,
      birthDate: userData.birthDate,
      birthTime: userData.birthTime,
      gender: userData.gender,
      timezone: userData.timezone,
      password_hash: hashedPassword
    });

    // 生成JWT令牌
    const token = generateToken({
      userId: user.id,
      email: user.email,
      uuid: user.uuid
    });

    logInfo('用户注册成功', { userId: user.id, email: user.email });

    // 返回用户信息（不包含密码）和令牌
    return {
      user: {
        id: user.id,
        uuid: user.uuid,
        username: user.username,
        email: user.email,
        phone: user.phone,
        avatarUrl: user.avatarUrl,
        birthDate: user.birthDate,
        birthTime: user.birthTime,
        gender: user.gender,
        timezone: user.timezone,
        isVip: user.isVip,
        createdAt: user.createdAt
      },
      token
    };
  } catch (error) {
    logError('用户注册失败', { error: error.message, email: userData.email });
    throw error;
  }
}

/**
 * 用户登录服务
 * @param {string} email - 用户邮箱
 * @param {string} password - 用户密码
 * @returns {Object} 包含用户信息和访问令牌的对象
 */
async function login(email, password) {
  try {
    // 查找用户
    const user = await User.findOne({
      where: {
        email: email
      }
    });

    if (!user) {
      logWarning('用户登录失败：用户不存在', { email: email });
      throw new Error('邮箱或密码错误');
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(password, user.password_hash);

    if (!isPasswordValid) {
      logWarning('用户登录失败：密码错误', { email: email });
      throw new Error('邮箱或密码错误');
    }

    // 生成JWT令牌
    const token = generateToken({
      userId: user.id,
      email: user.email,
      uuid: user.uuid
    });

    logInfo('用户登录成功', { userId: user.id, email: user.email });

    // 返回用户信息和令牌
    return {
      user: {
        id: user.id,
        uuid: user.uuid,
        username: user.username,
        email: user.email,
        phone: user.phone,
        avatarUrl: user.avatarUrl,
        birthDate: user.birthDate,
        birthTime: user.birthTime,
        gender: user.gender,
        timezone: user.timezone,
        isVip: user.isVip,
        createdAt: user.createdAt
      },
      token
    };
  } catch (error) {
    logError('用户登录失败', { error: error.message, email: email });
    throw error;
  }
}

/**
 * 验证用户认证状态
 * @param {string} token - JWT令牌
 * @returns {Object|null} 用户信息，如果验证失败则返回null
 */
async function authenticate(token) {
  try {
    // 验证JWT令牌
    const decoded = verifyToken(token);

    if (!decoded) {
      logWarning('用户认证失败：令牌无效');
      return null;
    }

    // 查找用户
    const user = await User.findByPk(decoded.userId);

    if (!user) {
      logWarning('用户认证失败：用户不存在', { userId: decoded.userId });
      return null;
    }

    logInfo('用户认证成功', { userId: user.id, email: user.email });
    
    // 返回用户信息
    return {
      id: user.id,
      uuid: user.uuid,
      username: user.username,
      email: user.email,
      phone: user.phone,
      avatarUrl: user.avatarUrl,
      birthDate: user.birthDate,
      birthTime: user.birthTime,
      gender: user.gender,
      timezone: user.timezone,
      isVip: user.isVip,
      createdAt: user.createdAt
    };
  } catch (error) {
    logError('用户认证失败', { error: error.message });
    return null;
  }
}

/**
 * 更新用户资料
 * @param {number} userId - 用户ID
 * @param {Object} updateData - 要更新的数据
 * @returns {Object} 更新后的用户信息
 */
async function updateProfile(userId, updateData) {
  try {
    // 查找用户
    const user = await User.findByPk(userId);

    if (!user) {
      logWarning('更新用户资料失败：用户不存在', { userId: userId });
      throw new Error('用户不存在');
    }

    // 如果提供了用户名且与当前用户名不同，检查用户名是否已存在
    if (updateData.username && updateData.username !== user.username) {
      const existingUsername = await User.findOne({
        where: {
          username: updateData.username
        }
      });

      if (existingUsername) {
        logWarning('更新用户资料失败：用户名已存在', { username: updateData.username });
        throw new Error('用户名已被使用');
      }
    }

    // 更新用户资料
    await user.update({
      username: updateData.username,
      avatarUrl: updateData.avatarUrl,
      birthDate: updateData.birthDate,
      birthTime: updateData.birthTime,
      timezone: updateData.timezone
    });

    logInfo('用户资料更新成功', { userId: user.id });

    // 返回更新后的用户信息
    return {
      id: user.id,
      uuid: user.uuid,
      username: user.username,
      email: user.email,
      phone: user.phone,
      avatarUrl: user.avatarUrl,
      birthDate: user.birthDate,
      birthTime: user.birthTime,
      gender: user.gender,
      timezone: user.timezone,
      isVip: user.isVip,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt
    };
  } catch (error) {
    logError('更新用户资料失败', { error: error.message, userId: userId });
    throw error;
  }
}

/**
 * 修改用户密码
 * @param {number} userId - 用户ID
 * @param {string} currentPassword - 当前密码
 * @param {string} newPassword - 新密码
 * @returns {boolean} 修改成功返回true
 */
async function changeUserPassword(userId, currentPassword, newPassword) {
  try {
    // 查找用户
    const user = await User.findByPk(userId);

    if (!user) {
      logWarning('修改密码失败：用户不存在', { userId: userId });
      throw new Error('用户不存在');
    }

    // 验证当前密码
    const isCurrentPasswordValid = await bcrypt.compare(currentPassword, user.password_hash);

    if (!isCurrentPasswordValid) {
      logWarning('修改密码失败：当前密码错误', { userId: userId });
      throw new Error('当前密码错误');
    }

    // 验证新密码强度（至少8位，包含数字）
    if (!newPassword || newPassword.length < 8 || !/\d/.test(newPassword)) {
      logWarning('修改密码失败：新密码不符合要求', { userId: userId });
      throw new Error('新密码至少8位且包含数字');
    }

    // 对新密码进行哈希处理
    const hashedNewPassword = await bcrypt.hash(newPassword, SALT_ROUNDS);

    // 更新用户密码
    await user.update({
      password_hash: hashedNewPassword
    });

    logInfo('用户密码修改成功', { userId: user.id });

    return true;
  } catch (error) {
    logError('修改用户密码失败', { error: error.message, userId: userId });
    throw error;
  }
}

module.exports = {
  register,
  login,
  authenticate,
  updateProfile,
  changeUserPassword
};